package com.free.utils.crypt;

import com.free.exception.SystemRuntimeException;
import com.free.utils.CharsetUtils;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DESCrypt
{
    private static final String ALGORITHM = "DES/CBC/PKCS5Padding";
    private static final String KEY_ALGORITHM = "DES";
    private static final int KEY_LEN = 8;

    /**
     * 加密
     * 
     * @param src
     * @param key
     * 
     * @return 加密后的 16 进制字符串
     */
    public static String encrypt(String src, String key)
    {
        try
        {
            byte[] bkey = createKey(key);
            SecretKey securekey = createSecureKey(bkey);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, securekey, new IvParameterSpec(bkey));

            return Hex.encodeHexString(cipher.doFinal(src.getBytes(CharsetUtils.SYS_CHARSET))).toUpperCase();
        }
        catch (BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException
                | InvalidAlgorithmParameterException | IllegalBlockSizeException | NoSuchPaddingException e)
        {
            throw new SystemRuntimeException("解密出错", e);
        }
    }

    /**
     * 解密
     * 
     * @param hexString
     * @param key
     * 
     * @return
     */
    public static String decrypt(String hexString, String key)
    {
        try
        {
            byte[] bkey = createKey(key);
            SecretKey securekey = createSecureKey(bkey);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, securekey, new IvParameterSpec(bkey));

            return new String(cipher.doFinal(Hex.decodeHex(hexString.toCharArray())), CharsetUtils.SYS_CHARSET);
        }
        catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException
                | InvalidKeySpecException | DecoderException | InvalidAlgorithmParameterException | NoSuchPaddingException e)
        {
            throw new SystemRuntimeException("解密出错", e);
        }
    }

    
    // 生成安全 key
    private static SecretKey createSecureKey(byte[] bkey) throws InvalidKeyException, NoSuchAlgorithmException,
            InvalidKeySpecException
    {
        // 从原始密匙数据创建DESKeySpec对象
        DESKeySpec dks = new DESKeySpec(bkey);
        // 创建一个密匙工厂，然后用它把DESKeySpec转换成一个SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);

        return keyFactory.generateSecret(dks);
    }

    // 生成 key
    private static byte[] createKey(String key)
    {
        byte[] newKey = MD5Crypt.hash(key, CharsetUtils.SYS_CHARSET);
        return Hex.encodeHexString(newKey).substring(0, KEY_LEN).toUpperCase().getBytes(CharsetUtils.SYS_CHARSET);
    }

    
    // TEST
    public static void main(String[] args)
    {
        String str = "阿义12";
        String key = "litianping";
        str = DESCrypt.encrypt(str, key);
        System.out.println(str);
        
        Runnable r = () -> System.out.println(DESCrypt.decrypt("B9DC1793C378344A3DE71434164B85F1", key));
        List<Thread> ts = IntStream.range(0, 50).mapToObj(i -> new Thread(r)).collect(Collectors.toList());
        ts.stream().forEach(t -> t.start());
    }
    
}
